 /**
 * Description: 生成业务表业务实现类
 * Copyright:Copyright 2018 nfky.com. All rights reserved
 * @author:xk
 * @since:0.0.1
 * Create at:2018-01-18 下午 16:03:50
 *  
 * Modification History:
 * Date         Author      Version     Description
 * ------------------------------------------------------------------
 * 2018-01-18   xk       0.0.1     Initial
 */
package com.metro.generator.gen.service.impl;

import com.metro.core.dao.IMapper;
import com.metro.core.service.BaseServiceSupport;
import com.metro.core.service.ServiceException;
import com.metro.core.vo.LabelValue;
import com.metro.core.vo.ResultCode;
import com.metro.core.vo.inf.IResult;
import com.metro.paperless.common.beans.constant.PropertiesEnum;
import com.metro.generator.gen.beans.constant.GenConstant;
import com.metro.generator.gen.Generator;
import com.metro.generator.gen.GeneratorProperties;
import com.metro.generator.gen.beans.vo.CodeFileConfig;
import com.metro.generator.gen.beans.vo.GenTableColumn;
import com.metro.generator.gen.mapper.IGenTableColumnMapper;
import com.metro.generator.gen.util.GenUtil;
import com.metro.paperless.sys.beans.vo.SysAttachment;
import com.metro.paperless.sys.mapper.ISysAttachmentMapper;
import com.metro.utils.FreeMarkerUtil;
import com.metro.utils.StringUtil;
import com.metro.utils.zip.ZipUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import com.metro.generator.gen.mapper.IGenTableMapper;
import com.metro.generator.gen.service.inf.IGenTableService;
import com.metro.generator.gen.beans.vo.GenTable;

import java.io.*;
import java.util.*;

import static com.metro.generator.gen.beans.constant.GenConstant.DEFAULT_ENCODING;
import static com.metro.generator.gen.beans.constant.GenConstant.GEN_FILE_EXT;

 /**
 * 生成业务表业务实现类<br>
 *
 * @author xk
 * @since [0.0.1]
 * @version [0.0.1, 2018-01-18]
 */
@Service("genTableService")
public class GenTableService extends BaseServiceSupport<GenTable> implements IGenTableService{
    public static final String placeholderPrefix = "${";
    //生成业务表Mapper
    @Autowired
    private IGenTableMapper genTableMapper;
     @Autowired
     private IGenTableColumnMapper genTableColumnMapper;
     @Autowired
     private ISysAttachmentMapper sysAttachmentMapper;
    @Override
    public IMapper getMapper() {
        return genTableMapper;
    }

     /**
      * 获取代码生成器公共配置信息,
      * <p>格式化配置参数，将占位符替换成具体值
      * <p>如果是个包名，则同时生成一个_dir的路径名</p>
      * @return
      */
    private Map<String, Object> getGenParamAndFormat(GenTable table){
        Properties props = GeneratorProperties.loadGeneratorProperties();
        Map<String, Object> map = new HashedMap();
        log.debug("配置文件加载完成, properties: {}", props);
        map.put("table", table);
        Set<Object> keys = props.keySet();
        for(Object keyObj : keys) {
            String key = keyObj.toString();
            String value = props.get(key).toString();
            if(value.indexOf(placeholderPrefix) >= 0){
                value = FreeMarkerUtil.renderString(value, map);
                log.debug("[gen] 格式化参数：{}: {}==>{}", key, props.get(key), value);
            }
            map.put(key, value);

            //如果是个包名，则同时生成一个_dir的路径名
            if(value.indexOf("com.") == 0){
                key = key + "_dir";
                value = value.replaceAll("\\.", "/");
                map.put(key, value);
                log.debug("[gen] 格式化包名对应的路径 {}={}", key, value);
            }
        }
        map.put("className", table.getClassName());
        map.put("classNameLower", StringUtil.toCamelCase(table.getClassName()));
        map.put("classNameLowerCase", table.getClassName().toLowerCase());
        map.put("now", new Date());
        return map;
    }
     @Override
     public SysAttachment genCode(String ids) {
         SysAttachment attachment = new SysAttachment();
         try {
             String[] idArr = ids.split(",");
             String rootDir = PropertiesEnum.getPropertyValue(PropertiesEnum.FILE_UPLOAD_ROOT);
             String outFileDir = "generator" + File.separator+ System.currentTimeMillis();
             String genOutRootDir = rootDir + File.separator + outFileDir;
             for(String id : idArr){
                 GenTable entity = genTableMapper.getById(Long.valueOf(id));
                 Map<String, Object> dataMap = getGenParamAndFormat(entity);
                 log.debug("生成源代码,表名={}", entity.getTableName());
                 log.debug("配置信息:{}", dataMap);
                 genTableCode(genOutRootDir, dataMap);
             }
             String zipFile = genOutRootDir+".zip";
             ZipUtil.zip(genOutRootDir, zipFile, true);

             attachment.setPath(outFileDir.replaceAll("\\\\", "/")+".zip");
             attachment.setFileType("zip");
             attachment.setModuleName("generator");
             attachment.setOldName("源码文件");
             sysAttachmentMapper.save(attachment);
         } catch (Exception e) {
             log.error("生成代码失败", e);
             throw new ServiceException(ResultCode.ERROR);
         }
         return attachment;
     }

     private void genTableCode(String genOutRootDir, Map<String, Object> dataMap) throws IOException {
         String templateDir = GenConstant.getTemplateDir();
         log.debug("模板文件根路径：{}", templateDir);
         Resource resource = new ClassPathResource(templateDir);
         File rootDir = resource.getFile();
         log.debug("rootDir abs: {}", rootDir.getAbsoluteFile().getAbsolutePath());
         Collection<File> files = FileUtils.listFiles(rootDir, GEN_FILE_EXT, true);
         log.debug("模板文件：{}", files);
         Configuration config = Generator.newFreeMarkerConfiguration(rootDir);
         for(File file : files){
             CodeFileConfig codeFileConfig = Generator.buildCodeFileConfig(genOutRootDir, dataMap, rootDir, file);
             Template template = config.getTemplate(codeFileConfig.getTemplateName());
             Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(
                     codeFileConfig.getTargetFile()),DEFAULT_ENCODING));
             try {
                 template.process(dataMap, out);
                 out.close();
             } catch (TemplateException e) {
                 log.error("[gen] 模板渲染出错", e);
                 throw new ServiceException(e);
             }
         }

     }

     @Override
     public GenTable queryTableColumnFromDbSchema(String tableName) {

         GenTable genTable = genTableMapper.queryTableFromDbSchema(tableName);
         List<GenTableColumn> columns = genTableColumnMapper.queryColumnFromDbSchema(tableName);
         genTable.setColumns(columns);
         GenUtil.initTableAndColumn(genTable);
         return genTable;
     }

     @Override
     public List<LabelValue> queryAllTableAsLabelValue() {
         return genTableMapper.queryAllTableAsLabelValue();
     }

     @Override
    public IResult save(GenTable entity) {
        try {
            entity.setIsConfig(true);
            genTableMapper.save(entity);
            entity.setColumnsTableId();
//            genTableColumnMapper.batchSaveColumn(entity.getColumns());
            for (GenTableColumn column : entity.getColumns()){
                genTableColumnMapper.save(column);
            }
            return ResultCode.SUCCESS;
        } catch (Exception e) {
            log.error("新增生成业务表失败", e);
            throw new ServiceException(ResultCode.ERROR);
        }
    }

    @Override
    public IResult update(GenTable entity) {
        try {
            entity.setIsConfig(true);
            genTableMapper.update(entity);
            entity.setColumnsTableId();
            genTableColumnMapper.deleteByGenTableId(entity.getId());
            for (GenTableColumn column : entity.getColumns()){
                genTableColumnMapper.save(column);
            }
            return ResultCode.SUCCESS;
        } catch (Exception e) {
            log.error("修改生成业务表失败", e);
            throw new ServiceException(ResultCode.ERROR);
        }
    }

    @Override
    public IResult delete(Long id) {
        try {
            genTableMapper.delete(id);
            return ResultCode.SUCCESS;
        } catch (Exception e) {
            log.error("删除失败", e);
            throw new ServiceException(ResultCode.ERROR);
        }
    }

    @Override
    public IResult deleteByIds(String ids) {
        try {
            genTableMapper.deleteByIds(ids);
            String[] idArr = ids.split(",");
            for(String id : idArr){
                genTableColumnMapper.deleteByGenTableId(Long.valueOf(id));
            }
            return ResultCode.SUCCESS;
        } catch (Exception e) {
            log.error("删除失败", e);
            throw new ServiceException(ResultCode.ERROR);
        }
    }
}